package cn.exrick.xboot.modules.transport.controller;

import cn.exrick.xboot.common.exception.XbootException;
import cn.exrick.xboot.common.lock.Callback;
import cn.exrick.xboot.common.lock.RedisLockTemplate;
import cn.exrick.xboot.common.utils.BeanConverterUtil;
import cn.exrick.xboot.common.utils.PageUtil;
import cn.exrick.xboot.common.utils.ResultUtil;
import cn.exrick.xboot.common.utils.SecurityUtil;
import cn.exrick.xboot.common.vo.PageVo;
import cn.exrick.xboot.common.vo.Result;
import cn.exrick.xboot.common.vo.RoleDTO;
import cn.exrick.xboot.modules.base.enums.OrderStatusEnum;
import cn.exrick.xboot.modules.base.enums.PaymentStatusEnum;
import cn.exrick.xboot.modules.base.enums.RoleEnum;
import cn.exrick.xboot.modules.transport.entity.CompanyRoutes;
import cn.exrick.xboot.modules.transport.entity.Orders;
import cn.exrick.xboot.modules.transport.mapper.CompanyRoutesMapper;
import cn.exrick.xboot.modules.transport.param.*;
import cn.exrick.xboot.modules.transport.service.CompanyRoutesService;
import cn.exrick.xboot.modules.transport.vo.*;
import cn.exrick.xboot.modules.transport.service.OrdersService;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.*;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author gj
 */
@Slf4j
@RestController
@Api(tags = "订单表管理接口")
@RequestMapping("/xboot/orders")
@Transactional
public class OrdersController {

    @Autowired
    private OrdersService ordersService;
    @Autowired
    private SecurityUtil securityUtil;
    @Autowired
    private CompanyRoutesMapper companyRoutesMapper;
    @Autowired
    private RedisLockTemplate redisLockTemplate;


    @RequestMapping(value = "/get/{id}", method = RequestMethod.GET)
    @ApiOperation(value = "通过id获取")
    public Result<OrdersVo> get(@PathVariable Long id) {
        OrdersVo ordersvo = BeanConverterUtil.convertBean(ordersService.getOrderById(id), OrdersVo.class);
        return new ResultUtil<OrdersVo>().setData(ordersvo);
    }

    @RequestMapping(value = "/delByIds", method = RequestMethod.POST)
    @ApiOperation(value = "批量通过id删除")
    public Result<Object> delAllByIds(@RequestBody Long[] ids) {

        for (Long id : ids) {
            ordersService.removeById(id);
        }
        return ResultUtil.success("批量通过id删除数据成功");
    }

    @RequestMapping(value = "/getByCondition", method = RequestMethod.GET)
    @ApiOperation(value = "多条件分页获取")
    public Result<IPage<OrdersOutlineVo>> getByCondition(QueryOrdersParam param,
                                                         PageVo page){
        if(param.getSenderId() == null && param.getNodeId() == null){
            RoleDTO currentRole = securityUtil.getCurrUser().getCurrentRole();
            if (currentRole == null) {
                throw new XbootException("当前用户无角色信息");
            }
            //平台用户 传入发单人id
            if(RoleEnum.PLATFORM_UER.getValue().equals(currentRole.getRoleName())){
                param.setSenderId(securityUtil.getCurrUser().getId());
            }else if (currentRole.getRoleName().endsWith(RoleEnum.WAREHOUSE_ADMIN.getValue())){
                CompanyRoutes companyRoutes = companyRoutesMapper.selectOne(new LambdaQueryWrapper<CompanyRoutes>().eq(CompanyRoutes::getOriginWarehouseId, currentRole.getWarehouseId()));
                if (companyRoutes == null){
                    return new ResultUtil<IPage<OrdersOutlineVo>>().setData(null);
                }else {
                    param.setRouteId(companyRoutes.getId());
                }
            }
        }
        return new ResultUtil<IPage<OrdersOutlineVo>>().setData(ordersService.getByCondition(PageUtil.initMpPage(page), param));
    }


    @RequestMapping(value = "/userCreatesOrder", method = RequestMethod.POST)
    @ApiOperation(value = "用户下单接口")
    public Result<OrdersVo> userCreatesOrder(@Valid @RequestBody CreateOrdersParam param) {
        return new ResultUtil<OrdersVo>().setData(ordersService.userCreatesOrder(param));
    }

    /**
     * 用户 分享订单设置收货人接口
     */
    @RequestMapping(value = "/setOrderReceiverId", method = RequestMethod.POST)
    @ApiOperation(value = "分享订单设置收货人接口")
    public Result<OrdersVo> setOrderReceiverId(@Valid @RequestBody OrderReceiverParam param) {
        return new ResultUtil<OrdersVo>().setData(ordersService.setOrderReceiverId(param));
    }


    @RequestMapping(value = "/cancelOrder", method = RequestMethod.POST)
    @ApiOperation(value = "取消订单接口")
    public Result<OrdersVo> userCancelOrder(@RequestBody CancelOrdersParam cancelOrdersParam) {
        OrdersVo ordersVo = ordersService.userCancelOrder(cancelOrdersParam);
        return new ResultUtil<OrdersVo>().setData(ordersVo);
    }

    //GPS信息回调接口，用于更新订单状态为运输中
    @RequestMapping(value = "/gpsCallback", method = RequestMethod.POST)
    @ApiOperation(value = "GPS信息回调接口-临时")
    public Result<String> gpsCallback(@RequestBody GpsCallbackParam param) {
        Orders byId = ordersService.getById(param.getOrderId());
        byId.setStatus(OrderStatusEnum.InTransit.getValue());
        byId.setDeliveryTime(LocalDateTime.now());
        ordersService.updateById(byId);
        return new ResultUtil<String>().setData("");
    }

    @RequestMapping(value = "/paymentOrder/{orderId}", method = RequestMethod.POST)
    @ApiOperation(value = "订单支付，发起预支付")
    public Result<OrdersVo> paymentOrder(@PathVariable Long orderId) {
        Object ordersVo = redisLockTemplate.execute("订单支付", 3, null, TimeUnit.SECONDS, new Callback() {
            @Override
            public Object onGetLock() {
                return ordersService.paymentOrder(orderId);
            }

            @Override
            public Object onTimeout() {
                return null;
            }
        });
        if (ObjectUtil.isNotNull(ordersVo)){
            return new ResultUtil<OrdersVo>().setData((OrdersVo)ordersVo);
        }else {
            return new ResultUtil<OrdersVo>().setErrorMsg("服务器处理中，请重试。");
        }
    }


    @RequestMapping(value = "/userConfirmOrder/{orderId}", method = RequestMethod.POST)
    @ApiOperation(value = "用户确认收货接口")
    public Result<OrdersVo> userConfirmOrder(@PathVariable Long orderId) {
        return new ResultUtil<OrdersVo>().setData(ordersService.userConfirmOrder(orderId));
    }

    @RequestMapping(value = "/warehousesReceiveOrder", method = RequestMethod.POST)
    @ApiOperation(value = "仓点接单接口")
    public Result<OrdersVo> warehousesReceiveOrder(@RequestBody ReceiveOrdersParam receiveOrdersParam) {
        OrdersVo ordersVo = ordersService.warehousesReceiveOrder(receiveOrdersParam);
        return new ResultUtil<OrdersVo>().setData(ordersVo);
    }


    @RequestMapping(value = "/warehousesWayOrder", method = RequestMethod.POST)
    @ApiOperation(value = "仓点中转/达到 车辆确认接口")
    public Result<OrderCarNodeResultVo> warehousesWayOrder(@RequestBody WayOrderParam wayOrderParam) {
        return new ResultUtil<OrderCarNodeResultVo>().setData(ordersService.warehousesWayOrder(wayOrderParam));
    }

    //统计报表
    @RequestMapping(value = "/report", method = RequestMethod.GET)
    @ApiOperation(value = "统计报表")
    public Result<List<OrdersReportVo>> report(OrderReportParam param) {
        return new ResultUtil<List<OrdersReportVo>>().setData(ordersService.report(param));
    }

    @GetMapping("/reportExport")
    @ApiOperation(value = "统计报表导出")
    public void reportExport(HttpServletResponse response,OrderReportParam param) throws IOException {
        List<OrdersReportVo> report = ordersService.report(param);
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setHeader("Content-Disposition", "attachment;filename=统计报表.xlsx");
        EasyExcel.write(response.getOutputStream(), OrdersReportVo.class)
                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) // 自动列宽
                .sheet("报表")
                .doWrite(report);
    }
    //应付统计
    @GetMapping("/payableReport")
    @ApiOperation(value = "应付报表")
    public Result<List<PayableReportVo>> getPayableReport(@RequestParam(required = false) String reportDate) {
        return new ResultUtil<List<PayableReportVo>>().setData(ordersService.getPayableReport(reportDate));
    }

    @GetMapping("/payableReportExport")
    @ApiOperation(value = "应付报表导出")
    public void payableReportExport(HttpServletResponse response,@RequestParam(required = false) String reportDate) throws IOException {
        List<PayableReportVo> payableReport = ordersService.getPayableReport(reportDate);
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setHeader("Content-Disposition", "attachment;filename=应付报表.xlsx");
        EasyExcel.write(response.getOutputStream(), PayableReportVo.class)
                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) // 自动列宽
                .sheet("应付报表")
                .doWrite(payableReport);
    }

    //应收统计
    @GetMapping("/receivableReport")
    @ApiOperation(value = "应收报表")
    public Result<List<ReceivableReportVo>> getReceivableReport(
            @RequestParam(required = false) String reportDate) {
        return new ResultUtil<List<ReceivableReportVo>>().setData(ordersService.getReceivableReport(reportDate));
    }

    @GetMapping("/receivableReportExport")
    @ApiOperation(value = "应收报表导出")
    public void receivableReportExport(HttpServletResponse response,@RequestParam(required = false) String reportDate) throws IOException {
        List<ReceivableReportVo> receivableReport = ordersService.getReceivableReport(reportDate);
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setHeader("Content-Disposition", "attachment;filename=应收报表.xlsx");
        EasyExcel.write(response.getOutputStream(), PayableReportVo.class)
                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) // 自动列宽
                .sheet("应收报表")
                .doWrite(receivableReport);
    }

    //收入统计
    @GetMapping("/incomeReport")
    @ApiOperation(value = "收入报表")
    public Result<List<IncomeReportVo>> getIncomeReport(
            @RequestParam(required = false) String reportDate) {
        return new ResultUtil<List<IncomeReportVo>>().setData(ordersService.getIncomeReport(reportDate));
    }

    @GetMapping("/incomeReportExport")
    @ApiOperation(value = "收入报表导出")
    public void incomeReportExport(HttpServletResponse response,@RequestParam(required = false) String reportDate) throws IOException {
        List<IncomeReportVo> incomeReport = ordersService.getIncomeReport(reportDate);
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setHeader("Content-Disposition", "attachment;filename=收入报表.xlsx");
        EasyExcel.write(response.getOutputStream(), PayableReportVo.class)
                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) // 自动列宽
                .sheet("收入报表")
                .doWrite(incomeReport);
    }


    //仓点应收统计
    @GetMapping("/warehouseReceivableReport")
    @ApiOperation(value = "仓点应收报表")
    public Result<List<PayableReportVo>> warehouseReceivableReport(@RequestParam(required = false) String reportDate) {
        return new ResultUtil<List<PayableReportVo>>().setData(ordersService.getPayableReport(reportDate));
    }

    @GetMapping("/warehouseReceivableReportExport")
    @ApiOperation(value = "仓点应收报表导出")
    public void warehouseReceivableReportExport(HttpServletResponse response,@RequestParam(required = false) String reportDate) throws IOException {
        List<PayableReportVo> payableReport = ordersService.getPayableReport(reportDate);
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setHeader("Content-Disposition", "attachment;filename=仓点应收报表.xlsx");
        EasyExcel.write(response.getOutputStream(), PayableReportVo.class)
                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) // 自动列宽
                .sheet("仓点应收报表")
                .doWrite(payableReport);
    }
}
